/*
 Copyright (c) Whitemice Consulting, 2007, 2008, 2009
 Adam Tauno Williams <awilliam@whitemice.org>
 License: MIT/X11

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using Gtk;
using Whitemice.Calendar;
using Whitemice.ZOGI;
using Whitemice.ZOGI.GtkWidgets;

namespace Whitemice.ZOGI.GtkFolios
{
  [System.ComponentModel.Category("Folios")]
  [System.ComponentModel.ToolboxItem(true)]
  public partial class DayStripController : Gtk.Bin, IZOGIWidget
  {   
    int rQ;
    
    public EntityEventHandler   OnViewEvent;
    public EntityEventHandler   OnEditEvent;
    public EntityEventHandler   OnDeleteEvent;
    public EntityEventHandler   OnDropEvent;
    public EntityEventHandler   OnCreateEvent;
    public MultiResultCallback  callback;
    
    protected PanelDialog       panelDialog = null;
    
    public DayStripController() : base()
    {
      this.Build();
      rQ = 0;
      days.Value = strip.Span;
      GUI.SetColorKey("ParticipatingEvent", new Gdk.Color(45, 200, 128));
      GUI.SetColorKey("ParticipatingBanner", new Gdk.Color(128, 200, 128));
      GUI.SetColorKey("ParticipatingBackground", new Gdk.Color(0, 0, 0));
      GUI.SetColorKey("NonVisibleEvent", new Gdk.Color(0, 0, 0));
      GUI.SetColorKey("NonVisibleBackground", new Gdk.Color(255, 255, 255));      
      callback = new MultiResultCallback(this.ReceiveDataCallback);
      strip.OnEventContext += new CalendarEventContextHandler(this.CalendarEventContextHandler);
      strip.OnEventDrop += new CalendarEventDropHandler(this.CalendarEventDropHandler);
      strip.OnStripContext += new CalendarContextHandler(this.CalendarContextHandler);
    }

    public IList<CalendarEvent> CalendarEvents 
    { 
      get { return strip.CalendarEvents; } 
    }
    
    public DateTime FirstDay
    {
      get { return strip.FirstDay; }
      set 
      { 
        strip.FirstDay = value;
        days.Value = strip.Span;
      }
    } // end FirstDay 
    
    public DateTime LastDay
    {
      get { return FirstDay.AddDays(Span); }
    } // end LastDay
    
    public int Span
    { 
      get { return strip.Span; }
      set { strip.Span = value; }
    }
    
    public void SetPositionToCurrent()
    {
      strip.SetPositionToCurrent();
    }
    
    public void RequestData(DateTime start, DateTime end, IList<Whitemice.ZOGI.Entity> panel)
    {
      int[] panelIds;
      
      panelIds = new int[panel.Count];
      for(int c = 0; c < panel.Count; c++)
      {
        panelIds[c] = panel[c].ObjectId;
      }
      RequestData(start, end, panelIds);
    } // end RequestData
    
    public void RequestData(DateTime start, DateTime end, int[] panel)
    {
      if (Server.Connection.Connected)
      {
        AppointmentSearchCommand  command;
        command = new AppointmentSearchCommand(start, 
                                               end, 
                                               null, 
                                               panel, 
                                               65535, 
                                               ++rQ);
        command.Callback = this.callback;
        Console.WriteLine("Strip requesing calendar data from server!");
        Server.Connection.RunCommand(command);
      } // end if-established 
    } // end ReloadData
    
    public void PushEventData(IList<Whitemice.ZOGI.Appointment> results)
    {
      Console.WriteLine("Day strip processing {0} events.", results.Count);
      strip.CalendarEvents.Clear();
      foreach(Whitemice.ZOGI.Appointment appointment in results)
      {
        if ((appointment.End > strip.FirstDay) && 
            (appointment.Start < strip.LastDay))
          strip.CalendarEvents.Add(new CalendarAppointment(appointment));
      } // end foreach in results
      strip.QueueDraw();
    } // end PushEventData
    
    public void ReceiveRPCCall(RPCEventArgs args) 
    {
      Console.WriteLine("Day strip received response from server.");
      if (args.HasResults)
      {
        if (((int)args.Context) == rQ)
        {
          IList<Whitemice.ZOGI.Appointment> list;
          list = new List<Whitemice.ZOGI.Appointment>();
          foreach(Whitemice.ZOGI.Entity entity in args.Payload)
          {
            if (entity.EntityName == "Appointment")
            {
              list.Add(entity as Whitemice.ZOGI.Appointment);
            }
          }
          if (list.Count > 0)
          {
            Application.Invoke(delegate { PushEventData(list); });
          }
        } else Console.WriteLine("Server response discarded"); // end if-this-is-a-current-response
      } // end if-exception-is-not-null
    } // end ReceiveData
    
    protected void MoveStrip(int _days)
    {
      Console.WriteLine("Move strip by {0} days.", _days);
      /* TODO: protect against running over MinValue and MaxValue */
      strip.FirstDay = strip.FirstDay.AddDays(_days);
      RequestData(strip.FirstDay, 
                  strip.FirstDay.AddDays(strip.Span + 2), 
                  new int[] { Server.Connection.UserId });
    } // end MoveStrip

    protected virtual void OnFastForwardClicked (object sender, System.EventArgs e)
    { MoveStrip(days.ValueAsInt); }

    protected virtual void OnForwardClicked (object sender, System.EventArgs e)
    { MoveStrip(1); }

    protected virtual void OnBackClicked (object sender, System.EventArgs e)
    { MoveStrip(-1); }

    protected virtual void OnFastBackClicked (object sender, System.EventArgs e)
    { MoveStrip(days.ValueAsInt * -1); }

    protected virtual void OnDaysValueChanged (object sender, System.EventArgs e)
    { Span = days.ValueAsInt;  }

    protected virtual void OnViewChanged (object sender, System.EventArgs e)
    {
      MoveStrip(0);
    }

    protected virtual void OnPanelChangeClicked (object sender, System.EventArgs e)
    {
      if (panelDialog == null) 
        panelDialog = new PanelDialog();
      panelDialog.Present();
    }
    
    protected virtual void CalendarEventContextHandler(CalendarEvent _event)
    {
      CalendarAppointment ev;
      PopUpMenuItem 	    menuItem;
      Menu                popupMenu;
      
      Console.WriteLine("Consonance - CalendarEventContextHandler");
      if (_event is CalendarAppointment)
      {
        ev = (_event as CalendarAppointment);
        if ((ev.Appointment.CanModify) || (ev.Appointment.CanRead))
        {
          popupMenu = new Menu();
          /* add Edit item */
          menuItem = new PopUpMenuItem(ev.Appointment, "Edit");
        	menuItem.Activated += new EventHandler(EventEdit);
        	if (ev.Appointment.CanModify)
				    menuItem.Sensitive = true;
				    else menuItem.Sensitive = false;
				  popupMenu.Append (menuItem);
				  /* add seperator */
				  popupMenu.Append (new SeparatorMenuItem ());
				  /* add Delete item */
          menuItem = new PopUpMenuItem(ev.Appointment, "Delete");
        	menuItem.Activated += new EventHandler(EventDelete);
        	if (ev.Appointment.CanModify)
				    menuItem.Sensitive = true;
				    else menuItem.Sensitive = false;
				  popupMenu.Append (menuItem);
				  /* add seperator */
				  popupMenu.Append (new SeparatorMenuItem ());
				  /* add View item */
          menuItem = new PopUpMenuItem(ev.Appointment, "View");
          menuItem.Activated += new EventHandler(EventView);
          if (ev.Appointment.CanRead)
  				  menuItem.Sensitive = true;
  				  else menuItem.Sensitive = false;
  				popupMenu.Append (menuItem);			
  				/* show poup menu */
				  popupMenu.Popup (null, null, null, 3, Gtk.Global.CurrentEventTime);
				  popupMenu.ShowAll();
        } /* if appointment deserves a popup menu */
          else Console.WriteLine("No access to appointment, refusing to present menu.");
      } /* end if appointment is a ZOGI appointment */
    } /* end CalendarEventContextHandler */
    
    protected virtual void EventEdit(object _sender, EventArgs _args)
    {
      Console.WriteLine("Edit appointment#{0}", (_sender as PopUpMenuItem).ContextObject.ObjectId);
      if (OnEditEvent != null)
        OnEditEvent((_sender as PopUpMenuItem).ContextObject, null, null);
    }
    
    protected virtual void EventDelete(object _sender, EventArgs _args)
    {
      Console.WriteLine("Edit appointment#{0}", (_sender as PopUpMenuItem).ContextObject.ObjectId);
      if (OnDeleteEvent != null)
        OnDeleteEvent((_sender as PopUpMenuItem).ContextObject, null, null);
    }
   
    protected virtual void EventView(object _sender, EventArgs _args)
    {
      Console.WriteLine("View appointment#{0}", (_sender as PopUpMenuItem).ContextObject.ObjectId);
      if (OnViewEvent != null)
        OnViewEvent((_sender as PopUpMenuItem).ContextObject, null, null);
    }
    
    protected virtual void CalendarEventDropHandler(CalendarEvent _event, DateTime _start)
    {
      CalendarAppointment ev;
      
      Console.WriteLine("Consonance -CalendarEventDropHandler");
      if (_event is CalendarAppointment)
      { 
        ev = (_event as CalendarAppointment);
        if (OnDropEvent != null)
          OnDropEvent(ev.Appointment, _start, null);       
      }
    }
    
    protected virtual void CalendarContextHandler(DayStrip _strip, DateTime _current)
    {
      MenuItem       	    menuItem;
      Menu                popupMenu;

      Console.WriteLine("Consonance - CalendarContextHandler");
      popupMenu = new Menu();
      if (OnCreateEvent != null)
      {
        /* add Create item */
        menuItem = new MenuItem("Create");
        menuItem.Activated += new EventHandler(EventCreate);
  		  popupMenu.Append (menuItem);
      }
      if (popupMenu.Children.Length > 0)
      {
		    popupMenu.Popup (null, null, null, 3, Gtk.Global.CurrentEventTime);
				popupMenu.ShowAll();
      }
    } /* end CalendarContextHandler */

    protected virtual void EventCreate(object _sender, EventArgs _args)
    {
      Whitemice.ZOGI.Appointment a;
      
      if (OnCreateEvent != null)
      {
        a = new Whitemice.ZOGI.Appointment();
        a.Start = DateTime.Now;
        a.End = a.Start.AddHours(1.0);
        OnCreateEvent(a, DateTime.Now, null);
      }
    } /* end EventCreate */
  }
}
